﻿using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Linq.Expressions;
using System.IO.Ports;
using System.IO;

namespace socketClient
{
    public partial class FrmClient : UIForm
    {
        public Socket clientSocket { get; set; }

        public FrmClient()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            //客户端连接服务器端
            //1、创建socket
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientSocket = socket;

            try
            {
                //2、连接服务器端
                socket.Connect(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text));
                ShowSuccessTip("连接成功");
            }
            catch (Exception ex)
            {
                ShowErrorTip(ex.Message);

                //使用递归时要注意，多次递归堆栈溢出的问题
                //Thread.Sleep(500);
                //btnStart_Click(this, e);
                return;
            }

            //3、发送消息，接收消息
            Thread thread = new Thread(new ParameterizedThreadStart(ReceiveData));
            thread.IsBackground = true;
            thread.Start(clientSocket);

        }

        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            if (clientSocket.Connected)
            {
                byte[] data = Encoding.UTF8.GetBytes(txtMsg.Text);
                clientSocket.Send(data,0,data.Length,SocketFlags.None);
            }
        }


        //往日志文本框上添加数据
        public void AppendTextToTxtLog(string txt)
        {
            if (txtLog.InvokeRequired) //判断是否跨线程访问
            {
                //Invoke同步方法      BeginInvoke异步方法
                txtLog.Invoke(new Action<string>(s =>
                {
                    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                }), txt);
            }
            else //本线程内访问
            {
                this.txtLog.Text = string.Format("{0}\r\n{1}", txt, txtLog.Text);
            }
        }


        public void ReceiveData(object socket)
        {
            byte[] data = new byte[500 * 1024 * 1024];
            var proxySocket = socket as Socket;
            while (true)
            {
                int len = 0;

                try
                {
                    len = proxySocket.Receive(data, 0, data.Length, SocketFlags.None);
                }
                catch (Exception ex)
                {
                    try
                    {
                        //服务器异常退出
                        AppendTextToTxtLog(string.Format("服务器端：{0}非正常退出", proxySocket.RemoteEndPoint.ToString()));
                    }
                    catch { }
                    stopConnect();  //停止连接
                    return; //让方法结束，结束当前接收数据的异步线程
                }

                //接收到0个字节代表客户端正常退出
                if (len <= 0)
                {
                    //服务器正常退出
                    AppendTextToTxtLog(string.Format("服务器端：{0}正常退出", proxySocket.RemoteEndPoint.ToString()));
                    stopConnect();  //停止连接
                    return; //让方法结束，结束当前接收数据的异步线程
                }

                if (data[0] == 1)
                {  //接收字符串
                    string str = Encoding.UTF8.GetString(data, 1, len - 1);
                    //把接收到的数据放到文本框上
                    AppendTextToTxtLog(string.Format("接收到服务器端：{0}的消息：{1}", proxySocket.RemoteEndPoint.ToString(), str));
                }
                else if (data[0] == 2)
                {
                    shake();
                }
                else if (data[0] == 3) 
                {
                    processReceiveFile(data,len);
                }
            }
        }

        private void processReceiveFile(byte[] data,int len)
        {
            using (SaveFileDialog sfd = new SaveFileDialog()) 
            {
                byte[] nameData = new byte[64];
                byte[] fileData = new byte[len - 1 - 64];
                Buffer.BlockCopy(data, 1, nameData, 0, 64);
                Buffer.BlockCopy(data, 1 + 64, fileData, 0, len - 1 - 64);
                string filename = Encoding.UTF8.GetString(nameData);
                sfd.FileName = filename;
                sfd.DefaultExt = "txt";
                sfd.Filter = "文本文件|*.txt|JPG|*.jpg|Doc|*.doc|所有文件|*.*";
                if(sfd.ShowDialog(this)!=DialogResult.OK)
                {
                    return;
                }
                File.WriteAllBytes(sfd.FileName,fileData);
            }
        }

        private void shake()
        {
            //记录窗体原始坐标
            Point oldLocation = this.Location;
            Random rand = new Random(); 

            for (int i = 0; i < 50; i++) {
                this.Location = new Point(
                    rand.Next(oldLocation.X-5,oldLocation.X+5),
                    rand.Next(oldLocation.Y-5,oldLocation.Y+5));
                Thread.Sleep(50);
                this.Location = oldLocation;

            }
        }

        private void stopConnect()
        {
            try
            {
                if (clientSocket.Connected)
                {
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close(100);

                }
            }
            catch (Exception ex) { 
                
            }
        }

        private string getIP()
        {
            //获取本机IP
            var hostName = Dns.GetHostName();
            var ipHost = Dns.GetHostEntry(hostName);
            var ipAddress = ipHost.AddressList.FirstOrDefault(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
            if (ipAddress != null)
            {
                var ipv4Address = ipAddress.ToString();
                Console.WriteLine("IPv4 Address: " + ipv4Address);
                return ipv4Address;
            }
            else
            {
                return null;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            txtIP.Text = getIP();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //判断是否已连接,如果已连接就关闭连接
            stopConnect();

        }
    }
}
